/* 重写数组的push方法 */
function fn1() {

    /*  */
    const originalPush = Array.prototype.push
    Array.prototype.push = function (...values) {
        // console.log(this);//谁来调用当前的push 此处的this就是谁

        for (let value of values) {
            if (this.indexOf(value) === -1) {
                // this[this.length] = value

                // arr.originalPush(value)
                originalPush.apply(this, [value])
            }
        }

        return this.length
    }

    const arr = [1, 2, 3]
    console.log(arr.push(2, 5), arr);//期望3,[1,2,3]
    console.log(arr.push(4, 6, 1, 8), arr);//4,[1,2,3,4]
}

/* 扩展数组方法 */
function fn2() {
    /* 给数组添加sum方法，对【符合条件的元素】求和 */
    Array.prototype.sum = function (filterFn) {
        let result = 0
        this.forEach(
            item => {
                if (filterFn(item)) {
                    result += item
                }
            }
        )
        return result
    }

    const arr = [1, 9, 2, "泥煤", 8, { name: "韦神", score: 3.14e2 }, 3, 7]

    /* 求所有数值的和 */
    console.log(
        arr.sum(
            (item) => typeof (item) === "number"
        )
    );//30

    /* 求及格成绩的和 */
    console.log(
        arr.sum(
            (item) => typeof (item) === "number" && item > 6
        )
    );//24
}

/* 管道/流水线 + 组合 */
function fn3() {

    function pipeline(...handlers) {
        // return 某种组合了所有handler的新函数
        return function (...args) {
            let result = args
            for (let handler of handlers) {
                result = handler(result)
            }
            return result
        }
    }

    function compose(...handlers) {
        // return 某种组合了所有handler的新函数
        return function (...args) {
            let result = args
            for (let i = handlers.length - 1; i > -1; i--) {
                const handler = handlers[i]
                result = handler(result)
            }
            return result
        }
    }

    console.log(
        pipeline(
            pig => `(电死了的${pig})`,
            arg => `(退了毛的${arg})`,
            arg => `(分割好的${arg})`,
            arg => `(熏制好的${arg})`
        )("一只猪")//熏制好的(分割好的(退了毛的(电死了的一只猪)))
    );

    console.log(
        compose(
            pig => `(电死了的${pig})`,
            arg => `(退了毛的${arg})`,
            arg => `(分割好的${arg})`,
            arg => `(熏制好的${arg})`
        )("一只猪")//熏制好的(分割好的(退了毛的(电死了的一只猪)))
    );

}

/* 管道与组合2 */
function fn4() {

    function pipeline(...handlers) {
        // return 某种组合了所有handler的新函数
        return function (...args) {
            return handlers.reduce(
                (pre, curr) => curr(pre),
                args
            )
        }
    }

    function compose(...handlers) {
        // return 某种组合了所有handler的新函数
        return function (...args) {
            return handlers.reduceRight(
                (pre, curr) => curr(pre),
                args
            )
        }
    }

    console.log(
        pipeline(
            pig => `(电死了的${pig})`,
            arg => `(退了毛的${arg})`,
            arg => `(分割好的${arg})`,
            arg => `(熏制好的${arg})`
        )("一只猪")//熏制好的(分割好的(退了毛的(电死了的一只猪)))
    );

    console.log(
        compose(
            pig => `(电死了的${pig})`,
            arg => `(退了毛的${arg})`,
            arg => `(分割好的${arg})`,
            arg => `(熏制好的${arg})`
        )("一只猪")//熏制好的(分割好的(退了毛的(电死了的一只猪)))
    );

}

/* 自带结果缓存的函数 */
function fn5() {
    const memory = (fn) => {

        const cacheMap = new Map()

        // 自带结果缓存的增强版fn
        return function mfn(...args) {
            console.log("cacheMap", cacheMap);

            let result = cacheMap.get(args.toString());
            console.log("result=", result);

            if (result === undefined) {
                console.log("开始高开销运算o(╥﹏╥)o...");
                result = fn.apply(null, args)
                cacheMap.set(args.toString(), result)
            }

            return result
        }

    }

    const power = (a, b) => {
        return Math.pow(a, b)
    }

    // 这是一个自带记忆功能的超集power
    const mPower = memory(power)

    console.log(mPower(10, 10));//第一次会真的计算，开销极大，性能极低，体验极差，所以我要缓存其结果！
    console.log(mPower(10, 10));//第二次直接拿缓存结果！速度飞快！

}

/* 柯里化 */
function fn6() {
    /* 慢慢凑齐龙珠 召唤神龙 */
    function curry(fn) {
        let dragonBalls = []

        return function cfn(...args) {
            dragonBalls = dragonBalls.concat(args)
            console.log("dragonBalls", dragonBalls);

            if (dragonBalls.length >= fn.length) {
                return fn.apply(null, dragonBalls)
            }

            return cfn
        }

    }

    const sum = (a, b, c, d, e, f, g) => {
        return a + b + c + d + e + f + g
    }

    const csum = curry(sum)
    console.log(
        csum(1, 2)(3, 4, 5)(6, 7) // fn 7
    );
    csum = null

}

~function main() {
    fn6()
}()